#pragma once

#include <set>
#include <memory>

#include <osg/Group>

#include "CmdHandler.h"

class INode;
class Face;
class Qt3DPicker;
class QtOSGWidget;
struct PlaneON;

namespace osg
{
	class Vec3d;
}

class Plane;
class ShxText;
class Scene;
class CmdHandler3 : public CmdHandler
{
	Q_OBJECT
public:
	// Q_INVOKABLE is necessary for QMetaObject::newInstance to work
	CmdHandler3();
	~CmdHandler3();

	virtual void onInit() override;

	QtOSGWidget* getWidget() const;
	Scene* getScene() const;
	Qt3DPicker* getPicker() const;

	void showRubberLine(bool val);
	void setRubberLineP1(const osg::Vec3d& pt);
	void setRubberLineP2(const osg::Vec3d& pt);
	void show3DRubberLine(bool val);
	void set3DRubberLineP1(const osg::Vec3d& pt);
	void set3DRubberLineP2(const osg::Vec3d& pt);

	bool getPoint2D(const Plane& plane, const QVariant& data, const QString& rawInput, CommandSource cs, osg::Vec3d& ucspt);
	void updateLastPoint(const Plane & plane, const osg::Vec3d& ucspt);
	bool isRubberLine2DVisible() const;
	bool isRubberLine3DVisible() const;

	osg::Vec4 getCurrentColor();

	// pt, nearPt, farPt all in WCS, nearPt is on near plane, farPt is on far plane
	// true - success, false - fail
	bool getNearFarPoint(const osg::Vec3d& pt, osg::Vec3d& nearPt, osg::Vec3d& farPt);
	// planePt is on plane, in Plane Coordinate System.
	bool getViewPointOnPlane(const Plane& plane, const osg::Vec3d& worldpt, osg::Vec3d& planePt);
	bool getViewPointOnPlane(const Plane& plane, const osg::Vec2d& dcsPt, const osg::Matrixd& invVPW, osg::Vec3d& planePt);
protected:
	bool m_clearSelectionOnExit = false;
	bool m_bDrawRubberLine = false;
	osg::Vec3d m_Point;
	osg::Vec3d m_Point2;
	osg::Vec3d m_3DPoint;
	osg::Vec3d m_3DPoint2;

private:
	void createRubberLine();
	void create3DRubberLine();
	void updateRubberLine();
	void update3DRubberLine();

	osg::Group* m_rubberLine = nullptr;
	osg::Group* m_rubberLine3D = nullptr;
	osg::Geometry* m_lines = nullptr;
	ShxText* m_lenText = nullptr;
	ShxText* m_angleText = nullptr;
	osg::Geometry* m_line3D = nullptr;
};

// planePt is on plane, in World Coordinate System.
void getProjPointOnPlane(const Plane& plane, const osg::Vec3d& worldPt, osg::Vec3d& planePt);
